package halberd.utils;

import halberd.data.Complex;

public class ComplexUtils {
	public static Complex plus(Complex a, Complex b) {
		double real = a.re + b.re;
		double imag = a.im + b.im;
		return new Complex(real, imag);
	}

	public static Complex minus(Complex a, Complex b) {
		double real = a.re - b.re;
		double imag = a.im - b.im;
		return new Complex(real, imag);
	}

	public static Complex times(Complex a, Complex b) {
		double real = a.re * b.re - a.im * b.im;
		double imag = a.re * b.im + a.im * b.re;
		return new Complex(real, imag);
	}

	public static Complex times(Complex a, double alpha) {
		return new Complex(alpha * a.re, alpha * a.im);
	}

	public static Complex reciprocal(Complex a) {
		double scale = a.re * a.re + a.im * a.im;
		return new Complex(a.re / scale, -a.im / scale);
	}

	public static Complex divides(Complex a, Complex b) {
		return times(a, reciprocal(b));
	}

	public static Complex exp(Complex a) {
		return new Complex(Math.exp(a.re) * Math.cos(a.im), Math.exp(a.re) * Math.sin(a.im));
	}

	public static Complex sin(Complex a) {
		return new Complex(Math.sin(a.re) * Math.cosh(a.im), Math.cos(a.re) * Math.sinh(a.im));
	}

	public static Complex cos(Complex a) {
		return new Complex(Math.cos(a.re) * Math.cosh(a.im), -Math.sin(a.re) * Math.sinh(a.im));
	}

	public static Complex tan(Complex a) {
		return divides(sin(a), cos(a));
	}

	public static double abs(Complex a) {
		return Math.hypot(a.re, a.im);
	}

	public static double phase(Complex a) {
		return Math.atan2(a.im, a.re);
	}

	public static Complex conjugate(Complex a) {
		return new Complex(a.re, -a.im);
	}

	public static Complex[] cconvolve(Complex[] x, Complex[] y) {

		if (x.length != y.length) {
			throw new RuntimeException("x,y length don't equal");
		}

		int N = x.length;

		Complex[] a = FFTUtils.fft(x);
		Complex[] b = FFTUtils.fft(y);

		Complex[] c = new Complex[N];
		for (int i = 0; i < N; i++) {
			c[i] = times(a[i], b[i]);
		}

		return FFTUtils.ifft(c);
	}

	public static Complex[] convolve(Complex[] x, Complex[] y) {
		Complex ZERO = new Complex(0, 0);

		Complex[] a = new Complex[2 * x.length];
		for (int i = 0; i < x.length; i++)
			a[i] = x[i];
		for (int i = x.length; i < 2 * x.length; i++)
			a[i] = ZERO;

		Complex[] b = new Complex[2 * y.length];
		for (int i = 0; i < y.length; i++)
			b[i] = y[i];
		for (int i = y.length; i < 2 * y.length; i++)
			b[i] = ZERO;

		return cconvolve(a, b);
	}
}
